#ifndef BLK_H
#define  BLK_H
#include <glib.h>
#include "mach.h"
struct BasicBlock;
struct BlockManager;

typedef struct BlockCtx {
    void *start;
    void *end;
    target_size_t (*exec) (MachineStatus *, void *, void *); //machine, start_ptr, end_ptr
    void (*free) (struct BlockCtx *ctx); // free ctx
} BlockCtx;

// end with jmp insn
typedef struct BasicBlock {
    guint addr;
    guint ex_cnt; // how many times this block executed?
    BlockCtx lc3_insn_blk;
    BlockCtx x86_insn_blk;
    struct BlockManager *blkmgr;
    void *machine_status;
    enum {
        BLK_EMPTY,
        BLK_LC3_LOADED,
        BLK_X86_LOADED,
    } status;
    target_size_t (*blk_exec) (struct BasicBlock *blk);
    int (*blk_translate) (struct BasicBlock *blk);
} BasicBlock;

typedef struct BlockManager {
    void *machine_status;
    GHashTable *blk_tab; // address -> basicblock
} BlockManager;

static inline target_size_t blk_exec (BasicBlock *blk) {
    return blk->blk_exec (blk);
}

static inline int blk_translate (BasicBlock *blk) {
    return blk->blk_translate (blk);
}

BlockManager *
blkmgr_init (void *machine_status);

BasicBlock *
blkmgr_get_block (BlockManager* mgr, guint addr);

BasicBlock *
blk_init (BlockManager* mgr, guint addr);

int
blk_destory (BlockManager* mgr, BasicBlock *blk);

int
blk_load_lc3 (BasicBlock *blk,  target_size_t (*exec) (MachineStatus* ,void *, void *), void (*free_ctx) (BlockCtx *));

#endif 